package com.zg.datapush.util;

import com.zg.datapush.constant.DataPushConstants;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Cron表达式工具类
 * @author zg
 */
@Slf4j
public class CronUtil {

    // 常用的cron表达式模板
    private static final Map<String, String> CRON_TEMPLATES = new HashMap<>();

    static {
        CRON_TEMPLATES.put("每分钟", "0 * * * * ?");
        CRON_TEMPLATES.put("每5分钟", "0 */5 * * * ?");
        CRON_TEMPLATES.put("每10分钟", "0 */10 * * * ?");
        CRON_TEMPLATES.put("每15分钟", "0 */15 * * * ?");
        CRON_TEMPLATES.put("每30分钟", "0 */30 * * * ?");
        CRON_TEMPLATES.put("每小时", "0 0 * * * ?");
        CRON_TEMPLATES.put("每2小时", "0 0 */2 * * ?");
        CRON_TEMPLATES.put("每6小时", "0 0 */6 * * ?");
        CRON_TEMPLATES.put("每12小时", "0 0 */12 * * ?");
        CRON_TEMPLATES.put("每天0点", "0 0 0 * * ?");
        CRON_TEMPLATES.put("每天6点", "0 0 6 * * ?");
        CRON_TEMPLATES.put("每天12点", "0 0 12 * * ?");
        CRON_TEMPLATES.put("每天18点", "0 0 18 * * ?");
        CRON_TEMPLATES.put("每周一0点", "0 0 0 ? * MON");
        CRON_TEMPLATES.put("每月1号0点", "0 0 0 1 * ?");
    }

    /**
     * 验证cron表达式是否有效
     */
    public static boolean isValidCron(String cronExpression) {
        if (cronExpression == null || cronExpression.trim().isEmpty()) {
            return false;
        }

        try {
            String[] parts = cronExpression.trim().split("\\s+");

            // Spring的cron表达式应该有6个部分：秒 分 时 日 月 周
            if (parts.length != 6) {
                return false;
            }

            // 简单验证每个部分的格式
            return isValidCronPart(parts[0], 0, 59) && // 秒
                   isValidCronPart(parts[1], 0, 59) && // 分
                   isValidCronPart(parts[2], 0, 23) && // 时
                   isValidCronPart(parts[3], 1, 31) && // 日
                   isValidCronPart(parts[4], 1, 12) && // 月
                   isValidCronPart(parts[5], 0, 7);    // 周（0和7都表示周日）

        } catch (Exception e) {
            log.warn("验证cron表达式失败: {}", cronExpression, e);
            return false;
        }
    }

    /**
     * 验证cron表达式的单个部分
     */
    private static boolean isValidCronPart(String part, int min, int max) {
        if (part == null || part.trim().isEmpty()) {
            return false;
        }

        part = part.trim();

        // 通配符
        if ("*".equals(part) || "?".equals(part)) {
            return true;
        }

        // 范围表达式 (如: 1-5)
        if (part.contains("-")) {
            String[] range = part.split("-");
            if (range.length == 2) {
                try {
                    int start = Integer.parseInt(range[0]);
                    int end = Integer.parseInt(range[1]);
                    return start >= min && end <= max && start <= end;
                } catch (NumberFormatException e) {
                    return false;
                }
            }
            return false;
        }

        // 步长表达式 (如: */5, 1-10/2)
        if (part.contains("/")) {
            String[] step = part.split("/");
            if (step.length == 2) {
                try {
                    Integer.parseInt(step[1]); // 验证步长是数字
                    return isValidCronPart(step[0], min, max);
                } catch (NumberFormatException e) {
                    return false;
                }
            }
            return false;
        }

        // 列表表达式 (如: 1,3,5)
        if (part.contains(",")) {
            String[] values = part.split(",");
            for (String value : values) {
                if (!isValidCronPart(value.trim(), min, max)) {
                    return false;
                }
            }
            return true;
        }

        // 单个数值
        try {
            int value = Integer.parseInt(part);
            return value >= min && value <= max;
        } catch (NumberFormatException e) {
            // 可能是星期的英文缩写 (MON, TUE, etc.)
            if (min == 0 && max == 7) { // 星期字段
                return part.matches("(?i)(MON|TUE|WED|THU|FRI|SAT|SUN)");
            }
            return false;
        }
    }

    /**
     * 获取常用cron表达式模板
     */
    public static Map<String, String> getCronTemplates() {
        return new HashMap<>(CRON_TEMPLATES);
    }

    /**
     * 根据描述获取cron表达式
     */
    public static String getCronByDescription(String description) {
        return CRON_TEMPLATES.get(description);
    }

    /**
     * 计算下次执行时间
     */
    public static Date getNextExecuteTime(String cronExpression) {
        if (!isValidCron(cronExpression)) {
            return null;
        }

        try {
            LocalDateTime now = LocalDateTime.now();
            String[] parts = cronExpression.trim().split("\\s+");

            // 解析各个部分
            String seconds = parts[0];
            String minutes = parts[1];
            String hours = parts[2];
            String dayOfMonth = parts[3];
            String month = parts[4];
            String dayOfWeek = parts[5];

            // 计算下次执行时间
            LocalDateTime next = calculateNextTime(now, seconds, minutes, hours, dayOfMonth, month, dayOfWeek);

            return Date.from(next.atZone(ZoneId.systemDefault()).toInstant());

        } catch (Exception e) {
            log.error("计算下次执行时间失败: {}", cronExpression, e);
            // 默认1小时后执行
            LocalDateTime next = LocalDateTime.now().plusHours(1);
            return Date.from(next.atZone(ZoneId.systemDefault()).toInstant());
        }
    }

    /**
     * 计算下次执行时间的核心逻辑
     */
    private static LocalDateTime calculateNextTime(LocalDateTime now, String seconds, String minutes,
                                                  String hours, String dayOfMonth, String month, String dayOfWeek) {
        LocalDateTime next = now.plusMinutes(1).withSecond(0).withNano(0);

        // 处理秒
        if (!"*".equals(seconds) && !"?".equals(seconds)) {
            if (seconds.startsWith("*/")) {
                // 格式: */n (每n秒)
                int interval = Integer.parseInt(seconds.substring(2));
                int currentSecond = now.getSecond();
                int nextSecond = ((currentSecond / interval) + 1) * interval;
                if (nextSecond >= 60) {
                    next = next.plusMinutes(1).withSecond(0);
                } else {
                    next = now.withSecond(nextSecond).withNano(0);
                    if (!next.isAfter(now)) {
                        next = next.plusMinutes(1);
                    }
                }
            } else if (seconds.contains("/")) {
                // 格式: n/m (从n开始，每m秒)
                String[] parts = seconds.split("/");
                int start = Integer.parseInt(parts[0]);
                int interval = Integer.parseInt(parts[1]);
                int currentSecond = now.getSecond();
                int nextSecond = start;
                while (nextSecond <= currentSecond) {
                    nextSecond += interval;
                }
                if (nextSecond >= 60) {
                    next = next.plusMinutes(1).withSecond(start);
                } else {
                    next = now.withSecond(nextSecond).withNano(0);
                    if (!next.isAfter(now)) {
                        next = next.plusMinutes(1);
                    }
                }
            } else {
                // 格式: n (固定秒)
                int targetSecond = Integer.parseInt(seconds);
                next = next.withSecond(targetSecond);
            }
        }

        // 处理分钟
        if (!"*".equals(minutes) && !"?".equals(minutes)) {
            if (minutes.startsWith("*/")) {
                // 格式: */n (每n分钟)
                int interval = Integer.parseInt(minutes.substring(2));
                int currentMinute = now.getMinute();
                int nextMinute = ((currentMinute / interval) + 1) * interval;
                if (nextMinute >= 60) {
                    next = next.plusHours(1).withMinute(0);
                } else {
                    next = next.withMinute(nextMinute);
                }
            } else if (minutes.contains("/")) {
                // 格式: n/m (从n开始，每m分钟)
                String[] parts = minutes.split("/");
                int start = Integer.parseInt(parts[0]);
                int interval = Integer.parseInt(parts[1]);
                int currentMinute = now.getMinute();
                int nextMinute = start;
                while (nextMinute <= currentMinute) {
                    nextMinute += interval;
                }
                if (nextMinute >= 60) {
                    next = next.plusHours(1).withMinute(start);
                } else {
                    next = next.withMinute(nextMinute);
                }
            } else {
                // 格式: n (固定分钟)
                int targetMinute = Integer.parseInt(minutes);
                next = next.withMinute(targetMinute);
                if (!next.isAfter(now)) {
                    next = next.plusHours(1);
                }
            }
        }

        // 处理小时
        if (!"*".equals(hours) && !"?".equals(hours)) {
            if (hours.startsWith("*/")) {
                // 格式: */n (每n小时)
                int interval = Integer.parseInt(hours.substring(2));
                int currentHour = now.getHour();
                int nextHour = ((currentHour / interval) + 1) * interval;
                if (nextHour >= 24) {
                    next = next.plusDays(1).withHour(0);
                } else {
                    next = next.withHour(nextHour);
                }
            } else if (hours.contains("/")) {
                // 格式: n/m (从n开始，每m小时)
                String[] parts = hours.split("/");
                int start = Integer.parseInt(parts[0]);
                int interval = Integer.parseInt(parts[1]);
                int currentHour = now.getHour();
                int nextHour = start;
                while (nextHour <= currentHour) {
                    nextHour += interval;
                }
                if (nextHour >= 24) {
                    next = next.plusDays(1).withHour(start);
                } else {
                    next = next.withHour(nextHour);
                }
            } else {
                // 格式: n (固定小时)
                int targetHour = Integer.parseInt(hours);
                next = next.withHour(targetHour);
                if (!next.isAfter(now)) {
                    next = next.plusDays(1);
                }
            }
        }

        // 处理日期（简化处理）
        if (!"*".equals(dayOfMonth) && !"?".equals(dayOfMonth)) {
            int targetDay = Integer.parseInt(dayOfMonth);
            next = next.withDayOfMonth(targetDay);
            if (!next.isAfter(now)) {
                next = next.plusMonths(1);
            }
        }

        // 确保计算出的时间在未来
        if (!next.isAfter(now)) {
            next = next.plusMinutes(1);
        }

        return next;
    }
}
